package cn.lxm.samples.resouces_server_1.config;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * 资源服务端
 */
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {


    private static final Logger logger = LoggerFactory.getLogger(ResourceServerConfiguration.class);

    private static final String COOKIE_TOKEN_NAME = "cookie_access_token";

    @Value("${sso.resource.id}")
    private String resourceId;

    @javax.annotation.Resource
    DataSource dataSource;

//    @Autowired
//    CookieTokenExtractor cookieTokenExtractor;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {

        resources.resourceId(resourceId);
        resources.tokenServices(defaultTokenServices());
        //设置自定义异常
//        resources.authenticationEntryPoint(new AuthExceptionEntryPoint())
//                .accessDeniedHandler(new CustomAccessDeniedHandler());
//        //加上Cookie验证，单页面应用不需要
//        resources.tokenExtractor(cookieTokenExtractor);

    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.requestMatcher(new OAuthRequestedMatcher()).authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll()
                .anyRequest().authenticated();
    }

    private static class OAuthRequestedMatcher implements RequestMatcher {
        public boolean matches(HttpServletRequest request) {
            String auth = request.getHeader("Authorization");
            // Determine if the client request contained an OAuth Authorization
            boolean haveOauth2Token = (auth != null) && auth.startsWith("Bearer");
            boolean haveAccessToken = request.getParameter("access_token") != null;
//            boolean haveCookieToken = extractHeaderToken(request);
            return haveOauth2Token || haveAccessToken;
        }
    }

//    private static boolean extractHeaderToken(HttpServletRequest request) {
//        Cookie[] cookies = request.getCookies();
//        if (cookies == null) {
//            return false;
//        }
//        for (Cookie cookie : cookies) {
//            if (COOKIE_TOKEN_NAME.equals(cookie.getName())) {
//                return "".equals(cookie.getValue().trim()) ? false : true;
//            }
//
//        }
//        return false;
//    }

    // ===================================================以下代码与认证服务器一致=========================================

    /**
     * 指定存储Token的方式
     *
     * @param accessTokenConverter
     * @return
     */
    @Bean
    public TokenStore tokenStore() {
//        TokenStore tokenStore = new JwtTokenStore(accessTokenConverter());
//        return tokenStore;
//        使用JDBCTokenStore清取消下面的注释
        return new JdbcTokenStore(dataSource);
    }

    /**
     * Token转换器必须与认证服务一致
     *
     * @return
     */
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        Resource resource = new ClassPathResource("publicKeys.txt");
        String publicKey = null;
        try {
            publicKey = inputStream2String(resource.getInputStream());
        } catch (final IOException e) {
            throw new RuntimeException(e);
        }
        converter.setVerifierKey(publicKey);
        return converter;
    }


    /**
     * 读取Key
     *
     * @param is
     * @return
     * @throws IOException
     */
    String inputStream2String(InputStream is) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(is));
        StringBuffer buffer = new StringBuffer();
        String line = "";
        while ((line = in.readLine()) != null) {
            buffer.append(line);
        }
        logger.info("读取Key");
        return buffer.toString();
    }


    /**
     * 创建一个默认的资源服务token
     *
     * @return
     */
    @Bean
    @Primary
    public ResourceServerTokenServices defaultTokenServices() {
        final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenEnhancer(accessTokenConverter());
        defaultTokenServices.setTokenStore(tokenStore());
        return defaultTokenServices;
    }

}